package com.hp.bon.sgw.core.route;

import java.util.ArrayList;
import java.util.Collections;

import com.hp.bon.sgw.Constants;
import com.hp.bon.sgw.Constants.NodeStatus;
import com.hp.bon.sgw.domain.Node;
import com.hp.bon.sgw.service.ConfigService;
import com.hp.bon.sgw.start.SpringContext;

public class RouteInfo
{
	public Node curNode; // next host
	// 如果统计超时比例为p,则按着(p/(p+1))的比例拒绝
	// 如果统计平均时延t大于T1(告警)，则按着(t-T1/T2-T1)的比例拒绝
	public double rejectPercent4SCID = 0.0;
	public int result;
	boolean isLoadBalance = false;
	public volatile ArrayList<RouteHopInfo> hopList = new ArrayList<RouteHopInfo>();
	ConfigService configService;
  public String scid;

  private RouteInfo()
  {
  }

  public RouteInfo(String scid)
  {
    this.scid = scid;
    this.configService = SpringContext.getInstance().getConfigService();
  }

	public void addRouteHopInfo(RouteHopInfo hop) {
		hopList.add(hop);
	}

	public RouteHopInfo findRouteHopInfo(Node node) {
		for (RouteHopInfo routeHopInfo : hopList) {
			if (routeHopInfo.node.equals(node))
				return routeHopInfo;
		}
		return null;
	}

	// 配置变更时
	public void checkRoute() {
		if (hopList.size() == 1) {
			curNode = hopList.get(0).node;
			return;
		}
		// 检查是否按优先级排序
		ArrayList<RouteHopInfo> tempList = (ArrayList<RouteHopInfo>) hopList.clone();
		Collections.sort(tempList);
		// 检查是否相同优先级,
		int curPriority = -1;
		int totalWeight = 0;
		isLoadBalance = true;
		for (RouteHopInfo hopInfo : tempList) {
			totalWeight += hopInfo.weight;
			if (curPriority == -1) {
				curPriority = hopInfo.priority;
			} else if (curPriority != hopInfo.priority) {
				isLoadBalance = false;
			}
		}
		// 如果配置的权重和为0，则不进行负载均衡
		if (totalWeight <= 0) {
			isLoadBalance = false;
		}
		if (isLoadBalance) {
			double range = 0.0;
			for (RouteHopInfo hopInfo : tempList) {
				range += hopInfo.weight / (totalWeight * 1.0);
				hopInfo.rangePercent = range;
			}
		}
		hopList = tempList;
  }

	/**
	 * 
	 * @param sessionId TODO
	 * @return
	 */
  public int calcNextHop()
  {
    this.result = 0;

		// 有负载均衡的做法如下
		if (isLoadBalance) {
			// 首先判断多个Node中是否存在拥塞，如果拥塞则排除
      boolean isStatusOk = true;
      for (RouteHopInfo next : this.hopList) {
        	if (next.node.getStatus() == NodeStatus.OFF_LINE || (next.node.getSendQueuePercent() > 0.5D)) {
          isStatusOk = false;
          break;
        }
      }
			// 如果多个节点都激活且没有下发拥塞，满足负载均衡条件，则按比例取对应Node,并直接返回结果
      if (isStatusOk) {
        double random = Math.random();
        for (RouteHopInfo next : this.hopList) {
          if (next.rangePercent >= random) {
            this.curNode = next.node;
            return this.result;
          }
        }
      }

    }
		//不满足负载均衡条件做法如下
    double MIN = this.configService.getIntValue("business.fluxctrl.send_queue_per", 50) * 0.1D;
    this.curNode = ((RouteHopInfo)this.hopList.get(0)).node;
    for (int i = 1; i < this.hopList.size(); i++) {
      Node nextNode = ((RouteHopInfo)this.hopList.get(i)).node;
      if ((this.curNode.getStatus() == 0) && (nextNode.getStatus() != 0)) {
        this.curNode = nextNode;
      }
      else if ((nextNode.getStatus() != 0) && 
        (this.curNode.getSendQueuePercent() > MIN) && 
        (this.curNode.getSendQueuePercent() > nextNode.getSendQueuePercent())) {
        this.curNode = nextNode;
      }
    }

    if (this.curNode.getStatus() != NodeStatus.OFF_LINE) {
      double rejectPercent4Node = 0.0D;
      if (this.curNode.getSendQueuePercent() > MIN) {
        rejectPercent4Node = (this.curNode.getSendQueuePercent() - MIN) / (1.0D - MIN);
      }

      double rejectPercent = this.rejectPercent4SCID > rejectPercent4Node ? this.rejectPercent4SCID : rejectPercent4Node;
      if (rejectPercent > 0.0D) {
        double random = Math.random();
        if (random < rejectPercent) {
          Constants.LOG.debug("no router because  rejectPercent :" + rejectPercent);
          this.result = 3002;
        }
      }
    } else {
      Constants.LOG.debug("no router because OFF_LINE :" + this.curNode.getHostId());
      this.result = 3002;
    }
    return this.result;
  }

	public static void main(String[] args) {
		RouteInfo route = new RouteInfo("test");
		Node node = new Node();
		route.addRouteHopInfo(new RouteHopInfo(node, 1, 30));
		route.addRouteHopInfo(new RouteHopInfo(node, 5, 30));
		route.addRouteHopInfo(new RouteHopInfo(node, 2, 30));
		route.addRouteHopInfo(new RouteHopInfo(node, 2, 50));
		route.checkRoute();
		System.out.println(route.hopList);
		node.setSendQueuePercent(0.6);
		route.checkRoute();
		System.out.println(1 / 3 + "," + (1.0 * 1) / 3 + "," + 1 / (3 * 1.0));
	}

	public void deleteHops(ArrayList<RouteHopInfo> deletehopList) {
		ArrayList<RouteHopInfo> newHopList = (ArrayList<RouteHopInfo>) hopList.clone();
		newHopList.removeAll(deletehopList);
		hopList = newHopList;
	}

}